---
title: 基于接口而非实现编程
---


基于接口而非实现编程，理解这条原则的时候，不要和具体的编程语言挂钩，局限在编程语言的接口语法中。


理解这条原则的关键，就是理解其中的“接口”两个字，从本质上来看，“接口”就是一组“协议”或者“约定”，是 <RedSpan>功能提供者提供给使用者的一个“功能列表”</RedSpan>。

“接口”在不同的应用场景下会有不同的解读，比如服务端与客户端之间的接口，类库提供的接口，甚至是一组通信协议都可以叫做“接口”。

如果落实到代码，可以理解为编程语言中的接口或者抽象类。

应用这条原则，可以将接口和实现相分离，封装不稳定的实现，暴露稳定的接口。上游系统面向接口而非实现编程，不依赖不稳定的细节，这样当实现发生变化的时候，上游系统的代码基本上不需要做改动，以此来降低耦合性，提高扩展性。


基于接口而非实现编程，这条原则的另一个表述方式是“基于抽象而非实现编程”。在软件开发中，最大的挑战之一就是需求的不断变化。

<RedSpan>越抽象、越顶层、越脱离某一实现的设计，越能提高代码的灵活性，越能应对未来的需求变化。抽象就是提高代码扩展性、灵活性、可维护性的最有效手段之一。</RedSpan>

具体来说，需要做到以下三点
* 函数的命名不能暴露任何实现细节。
* 封装具体的实现细节。
* 为实现类定义抽象的接口。

```java
public interface ImageStore {
  String upload(Image image, String bucketName);
  Image download(String url);
}

public class AliyunImageStore implements ImageStore {
  //...省略属性、构造函数等...

  public String upload(Image image, String bucketName) {
    createBucketIfNotExisting(bucketName);
    String accessToken = generateAccessToken();
    //...上传图片到阿里云...
    //...返回图片在阿里云上的地址(url)...
  }

  public Image download(String url) {
    String accessToken = generateAccessToken();
    //...从阿里云下载图片...
  }

  private void createBucketIfNotExisting(String bucketName) {
    // ...创建bucket...
    // ...失败会抛出异常..
  }

  private String generateAccessToken() {
    // ...根据accesskey/secrectkey等生成access token
  }
}

// 上传下载流程改变：私有云不需要支持access token
public class PrivateImageStore implements ImageStore  {
  public String upload(Image image, String bucketName) {
    createBucketIfNotExisting(bucketName);
    //...上传图片到私有云...
    //...返回图片的url...
  }

  public Image download(String url) {
    //...从私有云下载图片...
  }

  private void createBucketIfNotExisting(String bucketName) {
    // ...创建bucket...
    // ...失败会抛出异常..
  }
}

// ImageStore的使用举例
public class ImageProcessingJob {
  private static final String BUCKET_NAME = "ai_images_bucket";
  //...省略其他无关代码...

  public void process() {
    Image image = ...;//处理图片，并封装为Image对象
    ImageStore imageStore = new PrivateImageStore(...);
    imagestore.upload(image, BUCKET_NAME);
  }
}
```

## 是否需要为每个类定义接口？

这条原则的设计初衷时，将接口和实现分离，封装不稳定的实现，暴露稳定的接口。上有系统面向接口而非实现编程，不依赖不稳定的实现细节，这样当实现发生改变的时候，上有系统的代码基本上不需要改动，以此来降低代码间的耦合性，提高代码的可扩展性。

在这个设计初衷上来看，如果在业务场景中，某个功能只有一种实现方式，未来也不可能被其它实现方式替代，那么就没有必要为其设计接口，也没有必要基于接口编程，直接使用实现类就可以了。


